import { useState, useRef, useEffect, useCallback, useMemo } from "react";
import { Link, useLocation } from "react-router";
import { useDebounce } from "@react-hook/debounce";
import useEvent from "@react-hook/event";
import { compress } from "lzma-js-simple-v2";
import { toBase64 } from "fast-base64";
import { alert, type TextField } from "./mdui";
import { toast, copyText, hints } from "./utilities";
import { minifyHtml, minifyCSS, pretty } from "./code";

const CodeEdit = (properties: {
  title: string;
  lang: "html" | "css";
  value: string;
  hint: keyof typeof hints;
  onChange: (value: string) => void;
}) => {
  const textReference = useRef<TextField>(null);
  const hint = useMemo(() => {
    return hints[properties.hint][properties.lang];
  }, [properties.lang, properties.hint]);
  const inputCode = useCallback(
    (event: Event) => {
      properties.onChange(
        ((event as InputEvent).target as HTMLInputElement | null)?.value ?? "",
      );
    },
    [properties],
  );

  useEvent(textReference, "input", inputCode);

  return (
    <div
      style={{
        margin: 10,
      }}
    >
      <mdui-text-field
        rows={8}
        label={properties.title}
        ref={textReference}
        value={properties.value}
      ></mdui-text-field>
      <div
        className="flex-around"
        style={{
          margin: 5,
        }}
      >
        <mdui-button
          icon="compress"
          variant="elevated"
          onClick={() => {
            switch (properties.lang) {
              case "html": {
                minifyHtml(properties.value)
                  .then((code) => {
                    properties.onChange(code);
                  })
                  .catch((error) => {
                    toast(`压缩时出现错误: ${String(error)}`);
                  });
                break;
              }
              case "css": {
                minifyCSS(properties.value)
                  .then((code) => {
                    properties.onChange(code);
                  })
                  .catch((error) => {
                    toast(`压缩时出现错误: ${String(error)}`);
                  });
                break;
              }
            }
          }}
        >
          压缩
        </mdui-button>
        <mdui-button
          icon="code"
          variant="elevated"
          onClick={() => {
            pretty(properties.value, properties.lang)
              .then((code) => {
                properties.onChange(code);
              })
              .catch((error) => {
                toast(`格式化时出现错误: ${String(error)}`);
              });
          }}
        >
          格式化
        </mdui-button>
      </div>
      <div
        className="flex-around"
        style={{
          margin: 5,
        }}
      >
        <mdui-button
          icon="content_copy"
          variant="elevated"
          onClick={() => {
            void copyText(properties.value, () => {
              void alert({
                description: hint,
                confirmText: "好",
                closeOnOverlayClick: true,
              });
            });
          }}
        >
          复制
        </mdui-button>
        <mdui-button
          icon="clear"
          variant="elevated"
          onClick={() => {
            properties.onChange("");
          }}
        >
          清空
        </mdui-button>
      </div>
    </div>
  );
};

const CodeGenPage = () => {
  const [html, sethtml] = useDebounce("");
  const [css, setcss] = useDebounce("");
  const [codeUrl, setcodeUrl] = useState("");
  const [hint, setHint] = useState<keyof typeof hints>("via");
  const loc = useLocation();

  useEffect(() => {
    if (loc.state) {
      const data = loc.state as {
        html: string;
        css: string;
        hint: keyof typeof hints;
      };
      sethtml(data.html);
      setcss(data.css);
      setHint(data.hint);
    }
  }, [loc, setcss, sethtml]);

  return (
    <>
      <main>
        <CodeEdit
          title="HTML 代码"
          lang="html"
          value={html}
          hint={hint}
          onChange={(value) => {
            sethtml(value);
          }}
        />
        <CodeEdit
          title="自定义 CSS"
          lang="css"
          value={css}
          hint={hint}
          onChange={(value) => {
            setcss(value);
          }}
        />
        <div
          className="flex-around"
          style={{
            margin: 5,
          }}
        >
          <mdui-button
            onClick={() => {
              const data = JSON.stringify({ html, css, hint });
              if (html.length + css.length === 0) {
                toast("空代码");
                return;
              }
              compress(data, 9, (result) => {
                if (result.length > 0) {
                  toBase64(Uint8Array.from(result))
                    .then((encoded) => {
                      setcodeUrl(
                        location.origin +
                          location.pathname +
                          "code?code=" +
                          encoded,
                      );
                    })
                    .catch((error) => {
                      toast("编码时出现错误: " + String(error));
                    });
                } else {
                  toast("压缩时出现错误");
                }
              });
            }}
          >
            生成链接
          </mdui-button>
          {codeUrl === "" ? (
            <></>
          ) : (
            <mdui-button target="_blank" variant="text" href={codeUrl}>
              {`这是链接 (${String(codeUrl.length)})`}
            </mdui-button>
          )}
        </div>
        选择浏览器，用于复制后的指导信息
        <div style={{ margin: "5px auto" }}>
          {Object.keys(hints).map((value) => (
            <mdui-chip
              key={value}
              variant="filter"
              elevated
              selectable
              selected={hint === value ? true : void 0}
              style={{ margin: "5px" }}
              onClick={(event) => {
                event.currentTarget.setAttribute("selected", "");
                setHint(value as keyof typeof hints);
              }}
            >
              {hints[value as keyof typeof hints].name}
            </mdui-chip>
          ))}
        </div>
      </main>
      <footer>
        <Link to="/licenses" className="no-highlight">
          <mdui-button icon="info--outlined" variant="tonal">
            版本与依赖组件信息
          </mdui-button>
        </Link>
      </footer>
    </>
  );
};

export default CodeGenPage;
